#include "UpdateData.h"
#include "version.h"
#include <string.h>
#include "DeviceInfo.h"
#include "DeviceInfoBLL.h"
#include "UpdateBLL.h"
#include "Flash.h"
#include "usart.h"
#include "Tools.h"

static UpdatePackageInfo stUpdatePackageInfo;

UpdatePackageInfo *GetUpdatePackageInfo(void)
{
	return &stUpdatePackageInfo;
}

void InitUpdatePackageInfo(void)
{
	memset(&stUpdatePackageInfo, 0, sizeof(stUpdatePackageInfo));
}

//----------------------------------------------------------------------
typedef uint8_t (*UpudateSvrCmd)(void *data, uint32_t data_length, void *response_data, uint32_t *response_length);

static uint16_t request_svr_pakcage_index = 0;

//last package size, used for calculate update package total size
//prepare command get a package size from up machine, but when test
//there is a problem, when enter to bootloader, but last update failed
//then, reboot system, system is still in bootloader, then system can't
//received prepare update command, because prepare update command data
//style is app style. so, use a varity calculate package size
//because when there are no package, up machine don not send package
//and tell down machine to calculate crc, so, package size can calculate
//by down machine, there is no need get from up machine
static uint16_t last_package_size = 0;

static uint8_t PrepareUpdateSvrCommand(void *data, uint32_t data_length, void *response_data, uint32_t *response_length)
{
	SoftwareVersion soft_ver;
	HardwareVersion hard_ver;
	
	uint8_t ua8ResponseData[8];
	uint32_t u32Package_size = 0;
	
	GetDeviceSoftwareInfo(&soft_ver);
	GetDeviceHardwareInfo(&hard_ver);
	
	ua8ResponseData[0] = ePrepareUpdateRes;
	
	ua8ResponseData[1] = soft_ver.SfVers[0];
	ua8ResponseData[2] = soft_ver.SfVers[1];
	ua8ResponseData[3] = soft_ver.SfVers[2];
	
	ua8ResponseData[4] = hard_ver.HdVers[0];
	ua8ResponseData[5] = hard_ver.HdVers[1];
	ua8ResponseData[6] = hard_ver.HdVers[2];
	
	InitUpdateInfo();
	
	memcpy((void *)&u32Package_size, (void *)((uint8_t *)data + 8), sizeof(uint32_t));
	SetUpdatePackageInfo(u32Package_size);
	
//	STMFLASH_EraseSecter(UPDATEDATA_ADDR, UPDATEDATA_SCT_CNT);
//	STMFLASH_EraseSecter(UPDATEDATA_ADDR);
	request_svr_pakcage_index = 0;
	
	memcpy(response_data, ua8ResponseData, 8);
	*response_length = sizeof(ua8ResponseData);
	
	return 0;
}

static uint8_t StartUpdateSvrCommand(void *data, uint32_t data_length, void *response_data, uint32_t *response_length)
{
	uint8_t u8ModelID = GetSystemModelNum();
	uint8_t ua8ResponseData[9];
	
//	uint16_t u16ResponseCanID = MAKE_CANID(eRegularCmd, , u8ModelID);
	
	
	ua8ResponseData[0] = eStartUpdateRes;
	memcpy(ua8ResponseData + 1, &request_svr_pakcage_index, sizeof(request_svr_pakcage_index));
	
	//response system software version
	*response_length = sizeof(ua8ResponseData);
	memcpy(response_data, ua8ResponseData, sizeof(ua8ResponseData));
	
#if DEBUG
	printf("start update command!, rep can id:%0x, package index:%d\n\r", 
			u16ResponseCanID, request_svr_pakcage_index);
	
	for(int kk = 0; kk < data_length; kk++)
	{
		printf("%0x ", ((uint8_t *)data)[kk]);
	}
	printf("\r\n");
#endif
	
	request_svr_pakcage_index ++;

	//ResetSystem();
	return 0;
}

static uint8_t UpdateDataPackageSvrCommand(void *data, uint32_t data_length, void *response_data, uint32_t *response_length)
{
	uint8_t u8ModelID = GetSystemModelNum();
	uint8_t ua8ResponseData[9];
	
//	uint16_t u16ResponseCanID = MAKE_CANID(eRegularCmd, eStartUpdateRes, u8ModelID);
	
	
	ua8ResponseData[0] = eStartUpdateRes;
	memcpy(ua8ResponseData + 1, &request_svr_pakcage_index, sizeof(request_svr_pakcage_index));

	last_package_size = data_length;
	
	SavePackageToFlash(data, data_length);
	
	//response system software version
	*response_length = sizeof(ua8ResponseData);
	memcpy(response_data, ua8ResponseData, sizeof(ua8ResponseData));

#if DEBUG
	printf("start update command!, rep can id:%0x, package index:%d\n\r", 
			u16ResponseCanID, request_svr_pakcage_index);
	
	for(int kk = 0; kk < data_length; kk++)
	{
		printf("%0x ", ((uint8_t *)data)[kk]);
	}
	printf("\r\n");
#endif
	
	request_svr_pakcage_index ++;
	
	//ResetSystem();
	return 0;
}

static uint8_t UpdateCRCSvrCommand(void *data, uint32_t data_length, void *response_data, uint32_t *response_length)
{
	uint8_t u8ModelID = GetSystemModelNum();
	uint8_t ua8ResponseData[2] = {0};
	uint16_t u16PackageCRC = 0, u16LocalPackageCRC = 0;
	
//	uint16_t u16ResponseCanID = MAKE_CANID(eRegularCmd, eStartUpdateCrcRes, u8ModelID);
	
	memcpy(&u16PackageCRC, data, sizeof(u16PackageCRC));
	
	uint32_t received_total_package_size = (request_svr_pakcage_index - 2) * 256 + last_package_size;
//	SetUpdatePackageInfo(received_total_package_size);
	
	//if(received_total_package_size == GetUpdatePackageSize())
	{
		uint16_t package_cnt = (GetUpdatePackageSize() / PACKAGE_BUFF_SIZE);
		uint16_t remain_cnt = (GetUpdatePackageSize() % PACKAGE_BUFF_SIZE);
		uint8_t *tmpBuff = GetUpdatePackageBuff();
		uint8_t crcH = 0xFF, crcL = 0xFF;
		uint16_t cnt = 0;
		
		for(cnt = 0; cnt < package_cnt; cnt ++)
		{
			STMFLASH_Read(UPDATEDATA_ADDR + cnt * PACKAGE_BUFF_SIZE, 
						(uint32_t *)tmpBuff,PACKAGE_BUFF_SIZE / sizeof(uint32_t));
			
			u16LocalPackageCRC = CRC16_MODBUS(tmpBuff, PACKAGE_BUFF_SIZE, crcH, crcL);
			crcH = ((u16LocalPackageCRC >> 8) & 0xFF);
			crcL = (u16LocalPackageCRC & 0xFF);
			memset(tmpBuff, 0, PACKAGE_BUFF_SIZE);
		}
		
		if(remain_cnt)
		{
			STMFLASH_Read(UPDATEDATA_ADDR + cnt * PACKAGE_BUFF_SIZE, 
						(uint32_t *)tmpBuff, remain_cnt / sizeof(uint32_t) + 1);
			
			u16LocalPackageCRC = CRC16_MODBUS(tmpBuff, remain_cnt, crcH, crcL);
			memset(tmpBuff, 0, PACKAGE_BUFF_SIZE);
		}

		
		ua8ResponseData[0] = eStartUpdateCrcRes;
		ua8ResponseData[1] = (uint8_t)(u16PackageCRC == u16LocalPackageCRC?1:0);
		
		if(u16PackageCRC == u16LocalPackageCRC)
		{
//			SetDeviceUpdateFlag(true, false);
			SetFirmwareInfo(GetUpdatePackageSize(), u16PackageCRC, true);	//设置升级包信息
//			SEGGER_RTT_printf(0, "CRC OK, Update Flag = %d\r\n", GetUpdateFlag());
		}
		else
		{
			//if update failed, then change the flag to normal
			//but, attention this please, this may cause
			//unkwon problem
			SetDeviceUpdateFlag(false, true);
		}
	}
	
	
	//response system software version
	*response_length = sizeof(ua8ResponseData);
	memcpy(response_data, ua8ResponseData, sizeof(ua8ResponseData));
	
//	printf("update crc command!, rep can id:%0x, crc16 should be:%0x, I calculate is:%0x\n\r", 
//			u16ResponseCanID, u16PackageCRC, u16LocalPackageCRC);

	return 0;
}

static uint8_t CheckUpdateSvrCommand(void *data, uint32_t data_length, void *response_data, uint32_t *response_length)
{
	uint8_t u8ModelID = GetSystemModelNum();
	uint8_t ua8ResponseData[2];

	bool updateSvrRes = *((bool *)data);
	if(updateSvrRes == false)
	{
		response_data = NULL;
		*response_length = 0;
		return 0;
	}
	bool mvRes = MoveUpdateToApplication();

	
//	uint16_t u16ResponseCanID = MAKE_CANID(eRegularCmd, eCheckUpdateRes, u8ModelID);
	ua8ResponseData[0] = eCheckUpdateRes;
	ua8ResponseData[1] = (uint8_t)mvRes;
	
	//response system software version
//	CanDeviceSendData(u16ResponseCanID, ua8ResponseData, 1);
	
	*response_length = sizeof(ua8ResponseData);
	memcpy(response_data, ua8ResponseData, sizeof(ua8ResponseData));
	if(mvRes)
	{
		//升级成功，先跳转到App中去尝试运行一下试试，防止app错误，导致变砖
		if(GetDeviceTryStartTimes() == 0)
		{
			//设置尝试运行app次数为1
			SetDeviceTryStartTimes(1, true);
		}
		
//		printf("update check command!move application ok. rep can id:%0x\n\r", u16ResponseCanID);
		//如果成功启动，则由
		//app将启动次数置0，然后清零复位标志
		JumpToApplication(APPLCATION_ADDR);
	}
	
	//ResetSystem();
	return 0;
}


static UpudateSvrCmd updateSvrCmdSets[] = {PrepareUpdateSvrCommand, StartUpdateSvrCommand,
																						UpdateDataPackageSvrCommand,UpdateCRCSvrCommand, 
																						CheckUpdateSvrCommand};

uint8_t SvrCmdResponseProc(uint8_t cmd, void *data, uint32_t data_length, void *response_data, uint32_t *response_length)
{
	uint32_t u32CmdIndex = 0;
	
	if(cmd == eStartUpdate)
		u32CmdIndex = 1;
	else if(cmd == ePrepareUpdateRes)
		u32CmdIndex = 0;
	else if(cmd == eUpdateDataPackage)
		u32CmdIndex = 2;
	else if(cmd == eStartUpdateCrc)
		u32CmdIndex = 3;
	else if(cmd == eCheckUpdate)
		u32CmdIndex = 4;
	else
		return 0;
		
	updateSvrCmdSets[u32CmdIndex](data, data_length, response_data, response_length);
}



